package com.example.socket.codec;

import com.baidu.bjf.remoting.protobuf.Codec;
import com.baidu.bjf.remoting.protobuf.ProtobufProxy;
import com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass;
import com.example.socket.anno.impl.InBodyParameter;
import com.example.socket.exception.DecodeException;
import com.example.socket.handler.CommandInfo;
import com.example.socket.handler.TypeDefinition;
import com.google.protobuf.InvalidProtocolBufferException;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;

import java.io.IOException;
import java.lang.reflect.Type;

/**
 * @author yangjin
 */
public class JProtocolCoder extends CoderSupport {


    @Override
    public Object getInBody(Object body, InBodyParameter parameter) {
        return null;
    }

    @Override
    public Type getDefaultDecodeType() {
        return Object.class;
    }

    @Override
    public Type getDefaultEncodeType() {
        return Object.class;
    }

    @Override
    public Coder getClone() {
        return new JProtocolCoder();
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    protected byte[] doEncode(Object obj, Type type) {
        if (obj == null) {
            return new byte[0];
        }
        if (obj instanceof byte[]) {
            return (byte[]) obj;
        }
        try {
            Codec simpleTypeCodec = ProtobufProxy.create(obj.getClass());
            return simpleTypeCodec.encode(obj);
        } catch (Exception e) {
            String message = "JProtocolCoder编码失败:" + e.getMessage();
            logger.error(message, e);
            throw new DecodeException(message, e);
        }
    }

    @Override
    protected Object doDecode(byte[] bytes, Type type) {
//        if (ArrayUtils.isEmpty(bytes)) {
//            return null;
//        }
        if (type == null || type.equals(void.class) || type.equals(Object.class)) {
            return null;
        }
        try {
            Class<?> clazz = (Class<?>) type;
            Codec<?> simpleTypeCodec = ProtobufProxy.create(clazz);
            return simpleTypeCodec.decode(bytes);
        } catch (InvalidProtocolBufferException e) {
            String message = "JProtocolCoder解码失败:" + e.getMessage();
            logger.error(message);
            throw new DecodeException(message, e);
        } catch (IOException e) {
            FormattingTuple message = MessageFormatter.format(
                    "JProtocolCoder无法识别的类型[{}]", new Object[]{type, e});
            logger.error(message.getMessage());
            throw new DecodeException(message.getMessage(), e);
        }
    }

    @Override
    public void afterRegister(CommandInfo commandInfo) {
        TypeDefinition typeDefinition = commandInfo.getDefinition();
        doCache(typeDefinition.getRequest());
        doCache(typeDefinition.getResponse());
    }

    private void doCache(Type type) {
        if (type == null || type.equals(void.class) || type.equals(Object.class)) {
            return;
        }
        Class<?> clazz = (Class<?>) type;
        ProtobufClass protobufClass = clazz.getAnnotation(ProtobufClass.class);
        if (protobufClass != null && !clazz.isEnum()) {
            ProtobufProxy.create(clazz);
        }
    }
}